#ifndef request_h__
#define request_h__

#include "http_parser.h"
#include <iostream>
#include <string>

#include "boost/regex.hpp"
#include "boost/lexical_cast.hpp"

class request : 
	public http_parser
{
public:
	friend class http_connection;
	request():
	_header_field("")
	{
		http_parser_init(this, HTTP_REQUEST);
	}

	//return false if parse failed
	bool http_parse(const char* data, size_t len)
	{
		const static http_parser_settings settings
		{
			on_message_begin,
			on_url,
			on_status,
			on_header_field,
			on_header_value,
			on_headers_complete,
			on_body,
			on_message_complete
		};
		int ret = http_parser_execute(this, &settings, data, len);
		return ret == len;
	}

	//if param type don't match type T, it throw exception, catch exception!!!!!!!!!
	template<typename T>
	T get_param(const char* param) const
	{
		boost::smatch result;
		boost::regex rgx(param + std::string("=[^=]\\w+"));
		if (boost::regex_search(http_method::HTTP_GET == method ? _params : _body, result, rgx))
		{
			std::string v = result[0].str();
			return boost::lexical_cast<T>(v.substr(strlen(param) + 1, v.length()));
		}
		return T();
	}

	template<typename T>
	T get_param(boost::regex& rgx) const
	{
		boost::smatch result;
		if (boost::regex_search(http_method::HTTP_GET == method ? _params : _body, result, rgx))
		{
			std::string v = result[0].str();
			return boost::lexical_cast<T>(v.substr(v.find("=") + 1, v.length()));
		}
		return T();
	}

	std::string get_header_value(const char* field) const
	{
		auto it = _header.find(field);
		if (it != _header.end())
			return it->second;
		return "";
	}
private:
	static int on_message_begin(http_parser* self_)
	{
		return 0;
	}

	static int on_url(http_parser* self_, const char *data, size_t length)
	{
		((request*)self_)->_url = std::string(data, length);
// 		LOGT("get http reuqest: %s", ((request*)self_)->_url);
		if (http_method::HTTP_GET == self_->method)
		{
			parse_url_params((request*)self_);
			boost::replace_all(((request*)self_)->_params, "%2F", "/");
		}
		return 0;
	}
	static int on_status(http_parser* self_, const char *data, size_t length)
	{
// 		LOGI("get http reuqest: %s", std::string(data, length));
		return 0;
	}
	static int on_header_field(http_parser* self_, const char *data, size_t length)
	{
// 		LOGI("get http reuqest: %s", std::string(data, length));
		((request*)self_)->_header_field = std::string(data, length);
		return 0;
	}
	static int on_header_value(http_parser* self_, const char *data, size_t length)
	{
// 		LOGI("get http reuqest: %s", std::string(data, length));
		((request*)self_)->_header.insert(make_pair(((request*)self_)->_header_field, std::string(data, length)));
		return 0;
	}
	static int on_headers_complete(http_parser* self_)
	{
		((request*)self_)->_header_field = "";
		return 0;
	}
	static int on_body(http_parser* self_, const char *data, size_t length)
	{
		if (http_method::HTTP_POST == self_->method)
			((request*)self_)->_body = std::string(data, length);
		return 0;
	}
	static int on_message_complete(http_parser* self_)
	{
		return 0;
	}

	static void parse_url_params(request* self_)
	{
		auto pos = self_->_url.find_first_of('?');
		if(std::string::npos != pos)
		{
			self_->_params = self_->_url.substr(pos+1, self_->_url.length());
			self_->_url = self_->_url.substr(0, pos);
 		}
	}
public:
	std::string _body;
private:
	std::string _host;
	std::string _url;
	std::string _params;
	std::string _header_field;
	std::map<std::string, std::string> _header;
};
#endif // request_h__
